<template>
	<view class="wha d_f">
		<view class="">
			<canvas
				id="canvasMain"
				canvas-id="canvasMain"
				@mousedown="_mouseDown"
				@mousemove="_mouseMove"
				@mouseup="_mouseUp"
			></canvas>
			{{x}}-{{y}},{{touchStartX}}-{{touchStartY}}
		</view>
		<view class="tool_box">
			
			<!-- 图形按钮 -->
			<view class="operate_box o_a d_f_fsrwc">
				<view class="ml20 mt20" @click="_drawObject(item.type)" v-for="item in btns" :class="type == item.type ? 'btn_active' : '' ">
					<image class="btn_img" :src="item.src"></image>
					<view class="tac">{{item.name}}</view>
				</view>
			</view>
			
			<!-- 样式 -->
			<view class="operate_box o_a d_f_fsrwc">
				<view class="ml20 mt20" @click="_changeObjectStyle(item.type)" v-for="item in styleBtns" :class="type == item.type ? 'btn_active' : '' ">
					<image class="btn_img" :src="item.src"></image>
					<view class="tac">{{item.name}}</view>
				</view>
			</view>
			
			<!-- 颜色 -->
			<view class="operate_box o_a d_f_fsrwc">
				颜色
			</view>
			<!-- 层级 -->
			<view class="operate_box o_a d_f_fsrwc">
				层级
			</view>
			
			<!-- 输入 -->
			<view class="operate_box o_a d_f_fsrwc">
				<view class="">
					<input class="point_input" type="text"></input>
				</view>
			</view>
			
		</view>
		<!-- 
			a1 选择绘画类型
			a2 改图形背景样式
			a3 改图形背景色
			
			1 点击绘制	直线、曲线、波浪线、多边形
			2 拖动绘制	文字、箭头、三角形、梯形
			3 获取useId
			4 显示外框、变形点、旋转点
			单点变换，旋转，变形
			5 拖动换位置		计算拖拽框不能出范围
			6 拖动缩放
			7 换背景色、边框
			8 换背景图
			9 输入顶点、点击增加顶点（可选）
			10 变换层级
			11 保存
			12 框选、合并图层
			
			菜单操作：
				绘制
					点击绘制：
						直线
						曲线
						波浪线
						多边形
						文字
					拖拽绘制：	（移动距离大于5触发）
						箭头
						三角形
						梯形
					
				有useId的图形操作
					切换图层
					切换背景样式
					切换背景色
					输入点位
					删除
			
			canvas内操作：
				点击选中图形
					1）有useId时，绘制4条线和4个顶点（拖拽盒），点击时，
						1）先判断是否有已选中图形
							1) 如果有 判断点击位置
								1) 在图形上
									1) 在拖拽点上
										1) 拖拽缩放
									2) 在图形上
										1) 可变换位置（判断拖拽不能出区域）
								2) 在拖拽框上
									1) 顶点，获取是哪个点，
										1）0 右下
										2）1 右上
										3）2 左上
										4）3 左下
									2) 删除上
										1) 提示
											1) 删除
											2) 取消
								3) 在旋转点上
									1) 画旋转点
									2) 获取图形中心点
									3) 获取中心点到正上方旋转点向量，和鼠标位置到中心点向量之间的角度
								4) 在曲线的变换点上
								5) 没有 清空-1
							2) 没有 清空-1
						3) 清空-1
					2）没有usedId时
						1）判断是否在图形里（t1线段，t2文字，t3箭头，t4多边形）
							1）有就获取useId，算出拖拽盒4个顶点，绘制拖拽盒
							2）清空-1
				点击没选中图形
					1）清空-1
					
			注：
				清空-1：没有就清空useId和拖拽盒的顶点
		 -->
	</view>
</template>
<script>
	export default {
		name: 'canvasMain',
		props: [],
		data() {
			return {
				canvasW: 800,
				canvasH: 400,
				ctx: null,
				btns: [
					{
						name: '直线',
						src: require('@/static/canvas/line.png'),
						type: 'line'
					},{
						name: '弧线',
						src: require('@/static/canvas/curve.png'),
						type: 'curve'
					},{
						name: '波浪线',
						src: require('@/static/canvas/wave.png'),
						type: 'wave'
					},{
						name: '箭头',
						src: require('@/static/canvas/arrow.png'),
						type: 'arrow'
					},{
						name: '文字',
						src: require('@/static/canvas/text.png'),
						type: 'text'
					},{
						name: '三角形',
						src: require('@/static/canvas/triangle.png'),
						type: 'triangle'
					},{
						name: '梯形',
						src: require('@/static/canvas/trapezoid.png'),
						type: 'trapezoid'
					},{
						name: '多边形',
						src: require('@/static/canvas/polygon.png'),
						type: 'polygon'
					}
				],
				styleBtns: [
					{
						name: '没有背景',
						src: require('@/static/canvas/bg_none.png'),
						type: 'bg_none'
					},
					{
						name: '斜线背景',
						src: require('@/static/canvas/bg_line.png'),
						type: 'bg_line'
					},
					{
						name: '点阵背景',
						src: require('@/static/canvas/bg_point.png'),
						type: 'bg_point'
					}
				],
				pbl: 0,		// canvas与页面偏移量
				pbt: 0,
				x: 0,		// 鼠标位置
				y: 0,
				
				datas: [
					{ id: 'aaa',type: 'line',pit: [[130,350],[210,190],[280,150],[350,190],[430,350]],bg: 'f0f',lc: 'f00' },
					{ id: 'bbb',type: 'line',pit: [[220,200],[350,190],[350,260],[210,260]],bg: 'ff0',lc: '' },
					// { id: 'ccc',type: 'line',pit: [[120,200],[250,190]],bg: '',lc: '' },
					// { id: 'ddd',type: 'curve',pit: [[180,210],[260,110]],bg: '',lc: '' },
				],	// 所有画图内容存储
				// 状态管理
				type: '',	// 直线 line，曲线 curve，波浪线 wave，箭头 arrow，文字 text，三角形 triangle，梯形 trapezoid，多边形： polygon，
				isDrawing: false,
				
				// 被选中
				useId: 0,			// 被选中图形id
				dropR: 5,			// 拖拽盒顶点半径
				dropBox: [],		// 被选中图形的拖拽盒的4个顶点
				choseDrop: null,	// 4个顶点中被选中的那个
				
				ifObjMove: false,	// 图形移动
				
				touchStartX: 0,		// 鼠标拖拽启点
				touchStartY: 0,
			}
		},
		mounted() {
			this.getInfo();
			this.init();
		},
		methods: {
			getInfo() {
				let that = this;
				const query = uni.createSelectorQuery()
				query.select('#canvasMain').boundingClientRect(data => {
					// data为包含位置信息的对象
					that.pbl = data.left;
					that.pbt = data.top;
					// console.log('视图元素相对于页面顶部的距离', data.top, data.left);
				}).exec();
			},
			init(){
				let c = uni.createCanvasContext('canvasMain');	// canvas 实体
				this.ctx = c;
				this.draw();
			},
			_mouseDown(e) {
				let x = e.clientX - this.pbl,
					y = e.clientY - this.pbt;
				this.touchStartX = x;
				this.touchStartY = y;
					
				// 判断是否选中了图形		逻辑： 如果在拖拽框的点上，操作拖拽框，否则操作
				if( this.useId ) {	// 判断是否有已选中的对象图形，有这个才有拖拽框
					this.checkInDropTip(x,y);				// 是否点到拖拽框4个顶点上了
				}
				// 如果没点到拖拽框上，判断是否点到图形上了
				this.checkInObject(x,y);				// 判断是否点到图形上了
				if( this.useId ) {
					this.ifObjMove = true;
					this.drawDropBox();							// 获取拖拽盒4个顶点坐标
				} else {
					this.draw();
				}
			},
			_mouseMove(e) {
				let x = e.clientX - this.pbl,
					y = e.clientY - this.pbt;
				
				// 点了图形对象了
				if( this.useId && this.ifObjMove ) {
					this.objMove(x,y)
					this.touchStartX = x;
					this.touchStartY = y;
					
					// 点了拖拽框4个顶点之一了
					// if( this.choseDrop !== null ) {
						
					// 	return
					// }
				}
				this.x = x;
				this.y = y;
			},
			_mouseUp(e) {
				let x = e.clientX - this.pbl,
					y = e.clientY - this.pbt;
				this.ifObjMove = false;
				this.draw();
			},
			// 6 判断是否点在拖拽框的顶点，且获取是哪个
			checkInDropTip(x,y) {
				// 先判断是哪个点 顺序：右下、右上、左上、左下
				this.dropBox.map(( item, index ) => {
					if ( this. getDistance(item, [x,y]) < this.dropR ) {
						this.choseDrop = index;		// 返回被点的是哪个点
					}
				})
				return false;
			},
			// 6 是否在圈内的算法
			getDistance( p1, p2 ) {
				return Math.sqrt( ( p1[0] - p2[0] ) ** 2 + ( p1[1]- p2[1]) ** 2 );		// 距离公式
			},
			// 5 拖动换位置
			objMove(x,y){
				let id = this.useId;
				const item = this.datas.find( item =>  item.id == id );
				if( this.ifObjMove ) {
					item.pit.map( item => {
						item[0] += (x - this.touchStartX);
						item[1] += (y - this.touchStartY);
					})
					this.drawDropBox();		// 加上拖拽盒子跟着改变值并draw画出
				}
			},
			// ？ 计算多边形的中心点
			getObjCenter(lnglatarr) {
				var total = lnglatarr.length;
				var X = 0, Y = 0, Z = 0;
				lnglatarr.forEach(function (lnglat) {
					var lng = lnglat.lon * Math.PI / 180;
					var lat = lnglat.lat * Math.PI / 180;
					var x, y, z;
					x = Math.cos(lat) * Math.cos(lng);
					y = Math.cos(lat) * Math.sin(lng);
					z = Math.sin(lat);
					X += x;
					Y += y;
					Z += z;
				});
				X = X / total;
				Y = Y / total;
				Z = Z / total;

				var Lng = Math.atan2(Y, X);
				var Hyp = Math.sqrt(X * X + Y * Y);
				var Lat = Math.atan2(Z, Hyp);
				console.log(Lng, Lat, Hyp);
				return { lng: Lng * 180 / Math.PI, lat: Lat * 180 / Math.PI };
			},
			// 获取旋转点到中心点的向量和鼠标位置到中心点的向量的角度
			getCrossAngle() {
				
			},
			// -1 点空白时清空
			clearInfo() {
				this.touchStartX = 0;
				this.touchStartY = 0;
				this.useId = 0;
				this.dropBox = [];
				this.choseDrop = null;
			},
			// a1 选择绘画类型
			_drawObject(type) {
				this.type = type;
			},
			
			// a2 改图形背景样式
			_changeObjectStyle(type) {
				
			},
			// a3 改图形背景色
			_changeObjectBg(type) {
				
			},
			// 3 判断是否在元素内
			checkInObject(x,y) {
				let datas = this.deepClone(this.datas).reverse();		// 需要把图形数组顺序反过来
				let len = 0;
				datas.some( item => {
					if(this.IsPointInMatrix(item.pit,x,y)) {
						this.useId = item.id;
						// 显示拖拽框
						return true
					} else {
						// 点了空白的地方
						len += 1;
					}
				})
				if( len == datas.length ) {
					this.useId = '';
					this.dropBox = [];
				}
			},
			// 3 计算是否在对象图形内
			IsPointInMatrix( polygon, x, y ) {
				var inside = false;
				for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
					var xi = polygon[i][0], yi = polygon[i][1];
					var xj = polygon[j][0], yj = polygon[j][1];
					var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
					if (intersect)inside = !inside;
				}
				return inside;
			},
			// 绘制
			draw() {
				let c = this.ctx;
				c.clearRect(0, 0, this.canvasW, this.canvasH);
				this.datas.map(( item, index ) => {
					c.save();
					c.beginPath();
					
					// 边框颜色
					if( item.lc ) {
						c.strokeStyle = '#' + item.lc;
					}
					// 画直线
					if( item.type == 'line' ) {
						c.lineWidth = 1;
						item.pit.map(( ite, ind ) => {
							if( ind == 0 ) {
								c.moveTo( ite[0], ite[1] );
							} else {
								c.lineTo( ite[0], ite[1] );
							}
						})
					}
					c.closePath() 				// 闭合路径
					// 画曲线
					if( item.type == 'curve') {
						c.moveTo( item.pit[0][0], item.pit[0][1] )
						c.quadraticCurveTo( item.pit[0][0],item.pit[1][0], item.pit[1][1],  item.pit[1][0], item.pit[1][1]);
					}
					
					// 背景颜色
					if( item.bg ){
						c.fillStyle = '#' + item.bg;
						c.fill() 				// 填充颜色
						c.closePath() 			// 闭合路径
					}
					
					// c.closePath() 			// 闭合路径
					c.stroke()
					c.strokeStyle = '#000';
				})
				
				// 2 有选中时 画拖拽盒子
				if( this.dropBox ) {
					c.save();
					c.beginPath();
					c.strokeStyle = '#999';
					this.dropBox.map((item,index) => {
						if(index == 0)  c.moveTo( item[0],item[1] );
						else  c.lineTo( item[0],item[1] );
					})
					c.closePath() 				// 闭合路径
					c.stroke()
					
					// 四个点
					this.dropBox.map((item,index) => {
						c.beginPath();
						if(index == 2){
							c.fillStyle = '#999';
						} else {
							c.fillStyle = 'red'
						}
						c.lineWidth = 1;
						c.arc(item[0],item[1],this.dropR,0,2*Math.PI)
						c.closePath() 			// 闭合路径
						c.fill()
						c.stroke()
					})
					
					if ( this.useId ) {
						// 图形顶点
						const one = this.datas.find( item =>  item.id == this.useId );
						one.pit.map((item,index) => {
							c.beginPath();
							if(index == 2){
								c.fillStyle = '#999';
							} else {
								c.fillStyle = 'red'
							}
							c.lineWidth = 1;
							c.arc(item[0],item[1],this.dropR,0,2*Math.PI)
							c.closePath() 			// 闭合路径
							c.fill()
							c.stroke()
						})
						
						// 删除点
						c.beginPath();
						c.strokeStyle = 'red';
						c.lineWidth = 3;
						c.moveTo(this.dropBox[1][0] + 30,this.dropBox[1][1])
						c.lineTo(this.dropBox[1][0] + 10,this.dropBox[1][1] - 20)
						c.moveTo(this.dropBox[1][0] + 10,this.dropBox[1][1])
						c.lineTo(this.dropBox[1][0] + 30,this.dropBox[1][1] - 20)
						c.closePath() 			// 闭合路径
						c.stroke()
						
						// 旋转点
					}
				}
				
				c.draw();
			},
			// 4 获取拖拽框的顶点
			getDropVertex(pits) {
				let maxX,maxY,minX,minY;
				pits.map((item,index) => {
					if(index == 0){
						maxX = item[0];
						maxY = item[1];
						minX = item[0];
						minY = item[1];
					} else {
						if( item[0] > maxX ) maxX = item[0];
						if( item[1] > maxY ) maxY = item[1];
						if( item[0] < minX ) minX = item[0];
						if( item[1] < minY ) minY = item[1];
					}
				})
				return [[maxX + 10,maxY + 10],[maxX + 10,minY - 10],[minX - 10,minY - 10],[minX - 10,maxY + 10]]
			},
			// 4 画拖拽盒子
			drawDropBox() {
				// 通过id找到对象图形
				let id = this.useId;
				const item = this.datas.find( item =>  item.id == id );
				let pits = this.getDropVertex(item.pit)
				this.dropBox = pits;
				this.draw();
			},
			
			// 20 深度克隆
			deepClone (datas) {
				let obj = datas;
			    let objClone = Array.isArray(obj) ? [] : {};
			    if (obj && typeof obj === "object") {
			        for (var key in obj) {
			            if ( obj.hasOwnProperty(key) ) {
			                //判断ojb子元素是否为对象，如果是，递归复制
			                if (obj[key] && typeof obj[key] === "object") {
			                    objClone[key] = this.deepClone(obj[key]);
			                } else {
			                    //如果不是，简单复制
			                    objClone[key] = obj[key];
			                }
			            }
			        }
			    }
			    return objClone;
			},
		}
	}
</script>
<style>
	#canvasMain{
		width: 800px;
		height: 400px;
		margin-left: 30px;
		margin-top: 30px;
		border: 1px solid #ccc;
	}
	.tool_box{
		width: 300px;
		height: 50px;
		margin-left: 20px;
		margin-top: 20px;
	}
	.btn_img{
		width: 40px;
		height: 40px;
	}
	.btn_active{
		background-color: red;
	}
	.operate_box{
		width: 600px;
	}
	.point_input{
		border: 1px solid #ccc;
		padding: 4px;
	}
</style>